package org.example;

import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

public class ReverseProxyServer {

    private final int port;
    private final int clientPort;

    public ReverseProxyServer(int port, int clientPort) {
        this.port = port;
        this.clientPort = clientPort;
    }

    public void run() throws Exception {
        System.out.println("0000000000");
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
             .channel(NioServerSocketChannel.class)
             .childHandler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ch.pipeline().addLast(new ReverseProxyServerHandler(clientPort));
                 }
             });
            System.out.println("1111111");
            ChannelFuture f = b.bind(port).sync();
            f.channel().closeFuture().sync();
            System.out.println("222222222222");
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        int port = 9999; // 监听的端口
        int clientPort = 9998; // 接受来自机器B的连接端口
        new ReverseProxyServer(port, clientPort).run();
    }
}

class ReverseProxyServerHandler extends ChannelInboundHandlerAdapter {

    private final int clientPort;

    public ReverseProxyServerHandler(int clientPort) {
        this.clientPort = clientPort;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        new Thread(() -> {
            try {
                Bootstrap b = new Bootstrap();
                b.group(ctx.channel().eventLoop())
                 .channel(NioSocketChannel.class)
                 .handler(new ReverseProxyClientHandler(ctx.channel()));
                ChannelFuture cf = b.connect("localhost", clientPort).sync();
                cf.channel().closeFuture().sync();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).start();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ctx.writeAndFlush(msg);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

class ReverseProxyClientHandler extends ChannelInboundHandlerAdapter {

    private final Channel serverChannel;

    public ReverseProxyClientHandler(Channel serverChannel) {
        this.serverChannel = serverChannel;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        ctx.writeAndFlush(serverChannel.read());
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        serverChannel.writeAndFlush(msg);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}